#!/usr/bin/env python
# coding:utf-8

from opcua import Client
from opcua import ua
import json
import base64
import sys
path = sys.path[0]
path = path.replace("PipeServers","")
print("====", path, "====")
sys.path.append('./')
sys.path.append(path)
from Libs.PipeServer import *

# ======基础配置=======
_opcua_url = None
_opcua_timeout = 2 #300ms超时
_opcua_resend=6    #通讯重发次数
# =================


class OpcUaWorker:

    def __init__(self, url, timeout=2):
        """初始化OpcUaWorker"""
        self._url = url
        self._timeout = timeout                        
        
    def _set_node_value(self, client, taddr, val):
        '''写入寄存器'''
        try:
            tag = client.get_node("ns=2;s=" + taddr)
            # 写入寄存器
            
            dv = None
            if isinstance(val, dict):
                # 使用 value type 方式发送数值
                types = ["Int16","Int32","Int64","UInt16","UInt32","UInt64","Double","Float","String","Boolean"]
                if "value" in val and "type" in val:
                    if val['type'] in types:
                        ty = None
                        tv = None
                        ty = eval("ua.VariantType." + val['type'])
                        if val['type'] in ["Int16","Int32","Int64","UInt16","UInt32","UInt64"]:
                            tv = int(val['value'])
                        if val['type'] in ["Double","Float","Int64"]:
                            tv = float(val['value'])                           
                        if val['type'] in ["String"]:
                            tv = str(val['value'])
                        if val['type'] in ["Boolean"]:
                            if val['type'].lower() == 'true':
                                tv = True
                            else:
                                tv = False
                        dv  = ua.DataValue(ua.Variant(tv, ty))
                        tag.set_value(dv)
                        return True, ""
                    else:
                        #self.g_logger_queue.put(['error', "node value type must be [" + types + "]"])
                        print("node value type must be [" + types + "]")
                        return False, "node value type must be [" + types + "]"
                else:
                    #self.g_logger_queue.put(['error', "node value must have keys(value,type)"])
                    print("node value must have keys(value,type)")
                    return False, "node value must have keys(value,type)"
            else:
                # 使用 value 方式发送数值
                if isinstance(val, str):
                    dv  = ua.DataValue(ua.Variant(val, ua.VariantType.String))
                if isinstance(val, int):
                    dv  = ua.DataValue(ua.Variant(val, ua.VariantType.Int16))
                if isinstance(val, bool):
                    dv  = ua.DataValue(ua.Variant(val, ua.VariantType.Boolean))
                if isinstance(val, float):
                    dv  = ua.DataValue(ua.Variant(val, ua.VariantType.Float))
                if dv is None:
                    #self.g_logger_queue.put(['error', "value is not str or int [" + str(type(val)) + "]"])
                    print("value is not str or int [" + str(type(val)) + "]")
                    return False, "value is not str or int [" + str(type(val)) + "]"
                tag.set_value(dv)
                return True, ""
        except Exception as exp:
            #self.g_logger_queue.put(['error', "set_node_value exp [" + str(exp) + "]  [" + str(taddr) + "] [" + json.dumps(val) + "]"])
            print("set_node_value exp", exp)
            return False, str(exp)
        except Error as err:
            #self.g_logger_queue.put(['error', "set_node_value err [" + str(err) + "]  [" + str(taddr) + "] [" + json.dumps(val) + "]"])
            print("set_node_value err", err)
            return False, str(err)
            
    def _get_node_value(self, client, taddr):
        '''读寄存器'''
        try:
            tag = client.get_node("ns=2;s=" + taddr)
            # 写入寄存器
            return tag.get_value(), ""
        except Exception as exp:
            print(taddr)
            #self.g_logger_queue.put(['error', "get_node_value exp [" + str(exp) + "] [" + str(taddr) + "]"])
            print("get_node_value exp", exp)
            return None, "get_node_value exp "+ str(exp)
        except Error as err:
            #self.g_logger_queue.put(['error', "get_node_value err [" + str(err) + "] [" + str(taddr) + "]"])
            print("get_node_value err", err)
            return None, "get_node_value err "+ str(exp)
        pass

    def get_nodes_values(self, node_addrs, rtval):
        if isinstance(rtval, dict) == False:
            return False, "Param input rtval is not dict"
        client = Client(self._url, self._timeout)
        exp = ""
        try:
            client.connect()
            #data = {}
            for t in node_addrs:
                taddr = t
                value, exp = self._get_node_value(client, taddr)
                if value == None:
                    return False, str(exp)
                rtval[t] = value
            #rtval = data
        except Exception as exp:
            return False, str(exp)
        except Error as err:
            return False, str(err)
        finally:
            try:
                client.disconnect()
            except:
                pass
        return True, ""
        
    def set_nodes_values(self, node_addrs_values):
        if isinstance(node_addrs_values, dict) == False:
            return False, "Param input node_addrs_values is not dict"
        client = Client(self._url, self._timeout)
        exp = ""
        try:
            client.connect()
            for node in node_addrs_values:
                val = node_addrs_values[node]
                rt, exp = self._set_node_value(client, node, val)
                if rt == False:
                    return False, str(exp)
        except Exception as exp:
            print("set_nodes_values exp", exp)
            return False, str(exp)
        except Error as err:
            print("set_nodes_values err", err)
            return False, str(err)
        finally:
            try:
                client.disconnect()
            except:
                pass
        return True, ""
        
    def debug(self, url):
        client = Client(url, 2)       
        try:
            client.connect()
            node_addr = "CH2.TEST"
            SAT_STATUS_CODE = self.get_node_value(client, node_addr+".SAT_STATUS")
            SAT_ERRCODE = self.get_node_value(client, node_addr+".SAT_ERRCODE")
            print(SAT_STATUS_CODE, SAT_ERRCODE)
        except Exception as exp:
            pass
        finally:
            try:
                client.disconnect()
            except:
                pass

def onDataRecv(data):
    req = data 
    _opcua_url
    #wk = OpcUaWorker()
    #wk.debug(_opcua_url)
    
    #判定json格式
    try:
        args = json.loads(req)
    except ValueError as e:
        obj = {"errcode":2001, "rtval":None}
        exit(0)
        return json.dumps(obj)
    
    # {"action":"nodes_read", "param":["a","b","c"]}
    # {"action":"result_nodes_read", "success":true, "rtval":[xx,xx,xx]}
    # {"action":"nodes_write", "param":{"key":"val"}}
    # {"action":"result_nodes_write", "success":true}
    
    
    #判定json参数
    
    if "action" not in args:
        obj = {"errcode":2002, "rtval":None}
        return json.dumps(obj)
        
    if args['action'] not in ['nodes_read', 'nodes_write']:
        obj = {"errcode":2003, "rtval":None}
        return json.dumps(obj)
        
    act = args["action"]
    
    if act == 'nodes_read':
        if 'param' not in args:
            obj = {"errcode":2004, "rtval":None}
            return json.dumps(obj)
        if isinstance(args['param'], list) == False:
            obj = {"errcode":2005, "rtval":None}
            return json.dumps(obj)
            
        param = args['param']
        wk = OpcUaWorker(_opcua_url, _opcua_timeout)
        rtval = {}
        exp = ""
        rt, exp = wk.get_nodes_values(param, rtval)
        #rt = True
        #rtval = {"errcode":0, "rtval":"ha||h||a"}
        if rt==False:
            obj = {"errcode":2006, "rtval":exp}
            return json.dumps(obj)
            
        obj = {"errcode":0, "rtval":rtval}
        return json.dumps(obj)
    
    if act == 'nodes_write':
        if 'param' not in args:
            obj = {"errcode":2004, "rtval":None}
            return json.dumps(obj)
        if isinstance(args['param'], dict) == False:
            obj = {"errcode":2005, "rtval":None}
            return json.dumps(obj)
            
        param = args['param']
        wk = OpcUaWorker(_opcua_url, _opcua_timeout)
        rtval = {}
        exp = ""
        rt, exp = wk.set_nodes_values(param)
        #rt = True
        #rtval = {"errcode":0, "rtval":"ha||h||a"}
        if rt==False:
            obj = {"errcode":2006, "rtval":exp}
            return json.dumps(obj)
            
        obj = {"errcode":0, "rtval":""}
        return json.dumps(obj)
    '''        
    try:    
        data = base64.b64decode(bytes(args['data'], encoding='utf-8'));
        recv_len = args['recv_len'];
    except Exception as e:
        obj = {"errcode":2002, "rtval":None}
        return json.dumps(obj)

    #判定recv_len是数字
    if str(recv_len).isdigit():
        #通讯原始数据发送回收处理
        rep = comm_serial(data, recv_len)
        if rep == None:
            obj = {"errcode":2004, "rtval":None}
        else:
            if len(rep)!=recv_len:
                obj = {"errcode":2005, "rtval":str(base64.b64encode(rep), encoding='utf-8')}
            else:
                obj = {"errcode":0, "rtval":str(base64.b64encode(rep), encoding='utf-8')}
        #if int(pipeNumber)==1 and pipeName=="Pipe485S0":
        #    if rep!=None:
        #        new=[]
        #        for i in str(rep):
        #            new.append(ord(i))
        #        print(new)
        #    else:
        #        print( None)
        return json.dumps(obj)
    
    else:
        obj = {"errcode":2003, "rtval":None}
        return json.dumps(obj)
    '''
    obj = {"errcode":2003, "rtval":"aaaaa"}
    return json.dumps(obj)
    
    
    
if __name__ == "__main__":

    if len(sys.argv)<4:
        print("Not enough parameters  e.g. python3 opcua2pipe_server.py url PipeOPCUA 5")
        sys.exit()
        
    _opcua_url = sys.argv[1]
    pipeName   = sys.argv[2]
    pipeNumber = sys.argv[3]
    
    p = None
    if str(pipeNumber).isdigit():
        p = PipeServer(pipeName, int(pipeNumber), onDataRecv )
    else:
       print("pipeNumber must be number")
       sys.exit()


    print("OpcUaToPipeServer [", _opcua_url ,"] has been initialized ...")
    
    while True:
        time.sleep(10)
        
